﻿using ESRI.ArcGIS.Carto;
using ESRI.ArcGIS.Controls;
using ESRI.ArcGIS.DataSourcesFile;
using ESRI.ArcGIS.DataSourcesGDB;
using ESRI.ArcGIS.DataSourcesRaster;
using ESRI.ArcGIS.esriSystem;
using ESRI.ArcGIS.Geodatabase;
using ESRI.ArcGIS.Geoprocessing;
using ESRI.ArcGIS.Geoprocessor;
using ESRI.ArcGIS.SpatialAnalystTools;
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Text;
using System.Windows.Forms;

namespace School
{
    public partial class ConditionalFunction : Form
    {
        private readonly AxMapControl _mapControl;
        private readonly Geoprocessor _geoprocessor;
        private string _outputPath;

        public ConditionalFunction(AxMapControl mapControl)
        {
            InitializeComponent();
            _mapControl = mapControl;
            _geoprocessor = new Geoprocessor();
            _geoprocessor.OverwriteOutput = true;
            Load += ConditionalFunction_Load;
        }

        private void ConditionalFunction_Load(object sender, EventArgs e)
        {
            LoadLayersToComboBox();
            InitializeCompareComboBox();
            cboInput.SelectedIndexChanged += cboInput_SelectedIndexChanged;
            cboValue.SelectedIndexChanged += cboValue_SelectedIndexChanged;
        }

        private void InitializeCompareComboBox()
        {
            try
            {
                cboCompare.Items.Clear();
                cboCompare.Items.AddRange(new string[] {
                    "等于", "不等于", "大于", "大于等于", "小于", "小于等于"
                });
                cboCompare.SelectedIndex = 0;

                cboTrue.Items.Clear();
                cboTrue.Items.AddRange(new string[] { "0", "1" });
                cboTrue.SelectedIndex = 0;

                cboFalse.Items.Clear();
                cboFalse.Items.AddRange(new string[] { "0", "1" });
                cboFalse.SelectedIndex = 0;
            }
            catch (Exception ex)
            {
                MessageBox.Show("初始化比较运算符下拉框失败：" + ex.Message);
            }
        }

        public string GetSqlComparisonOperator()
        {
            if (cboCompare.SelectedItem == null)
                return "=";

            switch (cboCompare.SelectedItem.ToString())
            {
                case "等于": return "=";
                case "不等于": return "<>";
                case "大于": return ">";
                case "大于等于": return ">=";
                case "小于": return "<";
                case "小于等于": return "<=";
                default: return "=";
            }
        }

        private void LoadLayersToComboBox()
        {
            cboInput.Items.Clear();
            if (_mapControl.LayerCount <= 0) return;

            for (int i = 0; i < _mapControl.LayerCount; i++)
            {
                var layer = _mapControl.get_Layer(i);
                if (layer != null)
                {
                    cboInput.Items.Add(layer.Name);
                }
            }

            if (cboInput.Items.Count > 0)
            {
                cboInput.SelectedIndex = 0;
            }
        }

        private void cboInput_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                cboValue.Items.Clear();

                if (cboInput.SelectedItem == null) return;

                string selectedLayerName = cboInput.SelectedItem.ToString();
                IMap map = _mapControl.Map;
                ILayer layer = FindLayerByName(map, selectedLayerName);

                if (layer == null)
                {
                    MessageBox.Show("未找到选中的图层！");
                    return;
                }

                // 处理要素图层
                IFeatureLayer featureLayer = layer as IFeatureLayer;
                if (featureLayer != null)
                {
                    AddFieldsFromFeatureClass(featureLayer.FeatureClass);
                    return;
                }

                // 处理表格数据
                ITable table = layer as ITable;
                if (table != null)
                {
                    AddFieldsFromTable(table);
                    return;
                }

                // 处理栅格图层
                IRasterLayer rasterLayer = layer as IRasterLayer;
                if (rasterLayer != null)
                {
                    AddRasterBandInfo(rasterLayer);
                    return;
                }

                MessageBox.Show("选中的图层类型不支持或没有可用的字段信息！");
            }
            catch (Exception ex)
            {
                MessageBox.Show("获取字段失败：" + ex.Message);
            }
        }

        private void AddRasterBandInfo(IRasterLayer rasterLayer)
        {
            if (rasterLayer == null) return;

            IRaster raster = rasterLayer.Raster;
            if (raster == null) return;

            IRasterBandCollection rasterBands = raster as IRasterBandCollection;
            if (rasterBands == null) return;

            for (int i = 0; i < rasterBands.Count; i++)
            {
                IRasterBand rasterBand = rasterBands.Item(i);
                if (rasterBand != null)
                {
                    string bandName = $"波段_{i + 1}";
                    cboValue.Items.Add(bandName);
                }
            }

            IRasterProps rasterProps = raster as IRasterProps;
            if (rasterProps != null)
            {
                cboValue.Items.Add("宽度: " + rasterProps.Width);
                cboValue.Items.Add("高度: " + rasterProps.Height);
                cboValue.Items.Add("像素类型: " + rasterProps.PixelType.ToString());
            }

            if (cboValue.Items.Count > 0)
                cboValue.SelectedIndex = 0;
        }

        private void AddFieldsFromFeatureClass(IFeatureClass featureClass)
        {
            if (featureClass == null) return;

            for (int i = 0; i < featureClass.Fields.FieldCount; i++)
            {
                IField field = featureClass.Fields.get_Field(i);
                cboValue.Items.Add(field.Name);
            }

            if (cboValue.Items.Count > 0)
                cboValue.SelectedIndex = 0;
        }

        private void AddFieldsFromTable(ITable table)
        {
            if (table == null) return;

            for (int i = 0; i < table.Fields.FieldCount; i++)
            {
                IField field = table.Fields.get_Field(i);
                cboValue.Items.Add(field.Name);
            }

            if (cboValue.Items.Count > 0)
                cboValue.SelectedIndex = 0;
        }

        private ILayer FindLayerByName(IMap map, string layerName)
        {
            for (int i = 0; i < map.LayerCount; i++)
            {
                if (map.get_Layer(i).Name == layerName)
                {
                    return map.get_Layer(i);
                }
            }
            return null;
        }

        private void cboValue_SelectedIndexChanged(object sender, EventArgs e)
        {
            try
            {
                cboNum.Items.Clear();

                if (cboInput.SelectedItem == null || cboValue.SelectedItem == null)
                    return;

                string layerName = cboInput.SelectedItem.ToString();
                string fieldName = cboValue.SelectedItem.ToString();

                IMap map = _mapControl.Map;
                ILayer layer = FindLayerByName(map, layerName);
                if (layer == null) return;

                if (layer is IFeatureLayer featureLayer)
                {
                    GetFieldValues(featureLayer.FeatureClass, fieldName);
                }
                else if (layer is ITable table)
                {
                    GetFieldValues(table, fieldName);
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show("获取字段值失败: " + ex.Message);
            }
        }

        private void GetFieldValues(IFeatureClass featureClass, string fieldName)
        {
            if (featureClass == null) return;

            int fieldIndex = featureClass.FindField(fieldName);
            if (fieldIndex == -1) return;

            HashSet<string> uniqueValues = new HashSet<string>();

            IFeatureCursor featureCursor = featureClass.Search(null, true);
            IFeature feature = featureCursor.NextFeature();

            while (feature != null)
            {
                object value = feature.Value[fieldIndex];
                if (value != null)
                {
                    uniqueValues.Add(value.ToString());
                }
                feature = featureCursor.NextFeature();
            }

            if (featureCursor != null)
                Marshal.ReleaseComObject(featureCursor);

            foreach (string val in uniqueValues)
            {
                cboNum.Items.Add(val);
            }

            SortComboBoxItems();

            if (cboNum.Items.Count > 0)
                cboNum.SelectedIndex = 0;
        }

        private void GetFieldValues(ITable table, string fieldName)
        {
            if (table == null) return;

            int fieldIndex = table.FindField(fieldName);
            if (fieldIndex == -1) return;

            HashSet<string> uniqueValues = new HashSet<string>();

            ICursor cursor = table.Search(null, true);
            IRow row = cursor.NextRow();

            while (row != null)
            {
                object value = row.Value[fieldIndex];
                if (value != null)
                {
                    uniqueValues.Add(value.ToString());
                }
                row = cursor.NextRow();
            }

            if (cursor != null)
                Marshal.ReleaseComObject(cursor);

            foreach (string val in uniqueValues)
            {
                cboNum.Items.Add(val);
            }

            SortComboBoxItems();

            if (cboNum.Items.Count > 0)
                cboNum.SelectedIndex = 0;
        }

        private void SortComboBoxItems()
        {
            List<string> items = new List<string>();
            foreach (object item in cboNum.Items)
            {
                items.Add(item.ToString());
            }

            items.Sort();

            cboNum.Items.Clear();
            foreach (string item in items)
            {
                cboNum.Items.Add(item);
            }
        }


        private void ExecuteConditionalFunction(IRasterLayer inputRasterLayer, string sqlWhereClause, string trueValue, string falseValue, string outputPath)
        {
            IRasterDataset outputDataset = null;
            try
            {
                // 检查输入栅格
                if (inputRasterLayer == null || inputRasterLayer.Raster == null)
                {
                    throw new Exception("输入栅格无效");
                }

                // 确保输出目录存在
                string outputDir = System.IO.Path.GetDirectoryName(outputPath);
                if (!System.IO.Directory.Exists(outputDir))
                {
                    System.IO.Directory.CreateDirectory(outputDir);
                }

                // 使用GP工具前重置地理处理器
                _geoprocessor.ResetEnvironments();

                // 设置临时工作空间
                _geoprocessor.SetEnvironmentValue("workspace", outputDir);
                _geoprocessor.SetEnvironmentValue("scratchWorkspace", outputDir);

                // 创建Con工具实例
                Con conTool = new Con
                {
                    in_conditional_raster = inputRasterLayer,
                    in_true_raster_or_constant = double.Parse(trueValue),  // 条件为真时的值
                    in_false_raster_or_constant = double.Parse(falseValue), // 条件为假时的值
                    where_clause = sqlWhereClause,
                    out_raster = outputPath
                };

                // 执行工具
                IGeoProcessorResult result = _geoprocessor.Execute(conTool, null) as IGeoProcessorResult;

                // 检查执行结果
                if (result == null || result.Status != esriJobStatus.esriJobSucceeded)
                {
                    StringBuilder errorMsg = new StringBuilder("执行条件函数失败:\n");
                    for (int i = 0; i < _geoprocessor.MessageCount; i++)
                    {
                        errorMsg.AppendLine(_geoprocessor.GetMessage(i));
                    }
                    throw new Exception(errorMsg.ToString());
                }

            }
            catch (COMException comEx)
            {
                HandleComException(comEx);
            }
            catch (Exception ex)
            {
                MessageBox.Show("执行条件函数时出错: " + ex.Message);
            }
            finally
            {
                if (outputDataset != null)
                    Marshal.ReleaseComObject(outputDataset);
            }
        }

        private void AddRasterToMap(string rasterPath, string layerName)
        {
            IRasterWorkspace rasterWorkspace = null;
            IRasterDataset rasterDataset = null;
            IRasterLayer rasterLayer = null;

            try
            {
                // 检查文件是否存在
                if (!System.IO.File.Exists(rasterPath))
                {
                    throw new Exception("输出栅格文件不存在: " + rasterPath);
                }

                // 创建工作空间
                IWorkspaceFactory workspaceFactory = new RasterWorkspaceFactoryClass();
                string workspacePath = System.IO.Path.GetDirectoryName(rasterPath);
                string rasterName = System.IO.Path.GetFileName(rasterPath);

                rasterWorkspace = workspaceFactory.OpenFromFile(workspacePath, 0) as IRasterWorkspace;
                if (rasterWorkspace == null)
                {
                    throw new Exception("无法打开栅格工作空间");
                }

                // 打开栅格数据集
                rasterDataset = rasterWorkspace.OpenRasterDataset(rasterName);
                if (rasterDataset == null)
                {
                    throw new Exception("无法打开栅格数据集");
                }

                // 创建栅格图层
                rasterLayer = new RasterLayerClass();
                rasterLayer.CreateFromDataset(rasterDataset);
                rasterLayer.Name = layerName;

                // 添加到地图
                _mapControl.AddLayer(rasterLayer as ILayer, 0);
                _mapControl.ActiveView.Refresh();
            }
            catch (COMException comEx)
            {
                HandleComException(comEx);
            }
            catch (Exception ex)
            {
                MessageBox.Show("添加结果栅格到地图时出错: " + ex.Message);
            }
            finally
            {
                // 释放COM对象
                if (rasterLayer != null) Marshal.ReleaseComObject(rasterLayer);
                if (rasterDataset != null) Marshal.ReleaseComObject(rasterDataset);
                if (rasterWorkspace != null) Marshal.ReleaseComObject(rasterWorkspace);
            }
        }

        private void HandleComException(COMException comEx)
        {
            string errorMsg = "COM错误发生: " + comEx.ErrorCode.ToString("X") + "\n";
            errorMsg += "消息: " + comEx.Message + "\n";

            // 添加特定HRESULT处理
            switch (comEx.ErrorCode)
            {
                case -2147467259: // E_FAIL
                    errorMsg += "原因: 一般性失败，可能是数据无效或操作不支持";
                    break;
                case -2147220900: // 0x8004021C
                    errorMsg += "原因: 许可问题，请检查Spatial Analyst扩展是否可用";
                    break;
                case -2147220903: // 0x80040219
                    errorMsg += "原因: 内存不足或资源不足";
                    break;
                default:
                    errorMsg += "原因: 未知COM错误";
                    break;
            }

            MessageBox.Show(errorMsg);
        }

        private void btnRun_Click(object sender, EventArgs e)
        {
            try
            {
                if (cboInput.SelectedItem == null ||
                    cboValue.SelectedItem == null ||
                    cboCompare.SelectedItem == null ||
                    cboNum.SelectedItem == null ||
                    cboTrue.SelectedItem == null ||
                    cboFalse.SelectedItem == null)
                {
                    MessageBox.Show("请选择完整的条件参数！");
                    return;
                }

                string layerName = cboInput.SelectedItem.ToString();
                string fieldName = cboValue.SelectedItem.ToString();
                string operatorText = cboCompare.SelectedItem.ToString();
                string value = cboNum.SelectedItem.ToString();
                string trueValue = cboTrue.SelectedItem.ToString();
                string falseValue = cboFalse.SelectedItem.ToString();

                // 获取实际SQL运算符
                string sqlOperator = GetSqlComparisonOperator();

                // 构建栅格条件函数的SQL语句
                string sqlWhereClause = $"({fieldName} {sqlOperator} {value})";

                // 获取选中的图层
                ILayer selectedLayer = FindLayerByName(_mapControl.Map, layerName);
                if (selectedLayer == null)
                {
                    MessageBox.Show("未找到选中的图层！");
                    return;
                }

                // 检查是否为栅格图层
                IRasterLayer rasterLayer = selectedLayer as IRasterLayer;
                if (rasterLayer == null)
                {
                    MessageBox.Show("请选择栅格图层进行条件函数计算！");
                    return;
                }

                // 执行条件函数计算并保存结果
                ExecuteConditionalFunction(rasterLayer, sqlWhereClause, trueValue, falseValue, _outputPath);

                // 将结果添加到地图
                AddRasterToMap(_outputPath, "条件函数结果");
                MessageBox.Show("条件函数计算完成！结果已添加到地图。");
            }
            catch (Exception ex)
            {
                MessageBox.Show("执行计算时出错: " + ex.Message);
            }
        }



        private void btnOutput_Click(object sender, EventArgs e)
        {
            // 弹出保存对话框获取输出路径
            SaveFileDialog saveDlg = new SaveFileDialog();
            saveDlg.CheckPathExists = true;
            saveDlg.Filter = "TIF Files (*.tif)|*.tif";
            saveDlg.OverwritePrompt = true;
            saveDlg.Title = "保存条件结果";
            saveDlg.RestoreDirectory = true;
            if (cboInput.SelectedItem != null)
            {
                saveDlg.FileName = (string)cboInput.SelectedItem + "条件结果.tif";
            }

            DialogResult dr = saveDlg.ShowDialog();
            if (dr == DialogResult.OK)
            {
                _outputPath = saveDlg.FileName; 
                txtOutput.Text = _outputPath; 
            }
        }
    }
}